#include <string.h>

#include <utility>
#include "VDecoder.h"
#include "Util/logc.h"
namespace Media{
    VDecoder::VDecoder(int channel){
        m_videoDecoder = nullptr;
        m_channel = channel;
        m_frameConsumerIndex = 0;
    }

    VDecoder::~VDecoder(){

    }

    int VDecoder::GetChannel(){
        return m_channel;
    }

    bool VDecoder::Start(){
        

        return true;
    }
    
    bool VDecoder::Stop(){

        return true;
    }

    bool VDecoder::InputFrame(const FrameCommon::Frame::Ptr& frame){
        // std::lock_guard<std::recursive_mutex> guard(m_mux);
        if(!m_videoDecoder){
            VideoDecDesc decDesc;
            decDesc.card = 0;
            decDesc.channel = m_channel;
            if(createVideoDecoder(&decDesc, &m_videoDecoder) != 0){
                errorf("createVideoDecoder fail");
                return false;
            }
            VideoDecFormat format;
            memset(&format, 0, sizeof(VideoDecFormat));
            if(frame->codecId() == FrameCommon::H264){
                format.type = videoEncH264;
            }else if(frame->codecId() == FrameCommon::H265){
                format.type = videoEncH265;
            }else{
                errorf("unsupport codec type");
                m_videoDecoder->release(m_videoDecoder);
                m_videoDecoder = nullptr;
                return false;
            }
            
            m_videoDecoder->setFormat(m_videoDecoder, &format);
            m_videoDecoder->setFrameCb(m_videoDecoder, [](void *frame, void *arg){
                VDecoder *dthis = (VDecoder *)arg;
                if(dthis){
                    dthis->frameProc(frame);
                }
            }, this);

            if(m_videoDecoder->start(m_videoDecoder) != 0){
                errorf("video decoder start fail");
                m_videoDecoder->release(m_videoDecoder);
                m_videoDecoder = nullptr;
                return false;
            }

        }
        
        VideoDecPacket packet;
        packet.buffer = (uchar *)frame->data();
        packet.length = frame->size();
        packet.pts = frame->dts();

        m_videoDecoder->putPacket(m_videoDecoder, &packet);
        return true;
    }

    VDecoder::FrameConsumerId VDecoder::AddConsumer(std::function<void (const AVFrame::Ptr&)> consumer){
        tracef("VDecoder  AddConsumer");
        std::lock_guard<std::recursive_mutex> guard(m_mux);
        m_frameConsumerIndex++;
        FrameConsumerId id = m_frameConsumerIndex;
        m_frameConsumers[id] = std::move(consumer);
        return id;
    }

    bool VDecoder::RemoveConsumer(FrameConsumerId id){
        std::lock_guard<std::recursive_mutex> guard(m_mux);
        if(m_frameConsumers.find(id) == m_frameConsumers.end()){
            return false;
        }
        m_frameConsumers.erase(id);
        return true;
    }

    void VDecoder::ReleaseFrame(void *frame){
        if(m_videoDecoder)
            m_videoDecoder->releaseFrame(m_videoDecoder, frame);
    }

    void VDecoder::frameProc(void *frame){
        std::weak_ptr<VDecoder> wptr = shared_from_this();
        auto ptr = std::make_shared<AVFrame>(frame, true, [wptr](void *frame){
            auto vptr = wptr.lock();
            if(vptr){
                vptr->ReleaseFrame(frame);
            }
        });

        std::lock_guard<std::recursive_mutex> guard(m_mux);
        for(auto [_, value]: m_frameConsumers){
            value(ptr);
        }
    }
}